package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.zzyl.config.WebSocketServer;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.AlertNotifyDto;
import com.zzyl.entity.AlertData;
import com.zzyl.entity.AlertRule;
import com.zzyl.mapper.AlertDataMapper;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.mapper.NursingElderMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.AlertService;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DeviceDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 陈立功
 */
@Slf4j
@Service
public class AlertServiceImpl implements AlertService {

    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private NursingElderMapper nursingElderMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AlertDataMapper alertDataMapper;

    @Override
    public void checkAlarm(List<DeviceDataVo> deviceDataList) {
        // 检查某个设备的某个functionId的value是否异常
        for (DeviceDataVo data : deviceDataList) {
            String productKey = data.getProductKey();
            String iotId = data.getIotId();
            String functionId = data.getFunctionId();
            String dataValue = data.getDataValue();
            LocalDateTime alarmTime = data.getAlarmTime();
            // 获取对应当前数据的告警规则
            List<AlertRule> rules = alertRuleMapper.selectByProductKeyAndIotIdAndFunctionId(productKey, iotId, functionId);
            if (CollectionUtils.isEmpty(rules)) {
                continue;
            }
            // 计算是否出现告警
            for (AlertRule rule : rules) {
                // 判断时间，如果不在告警的时间段范围之内，就不处理
                String alertEffectivePeriod = rule.getAlertEffectivePeriod();
                if (StringUtils.isEmpty(alertEffectivePeriod)) {
                    continue;
                }
                String[] arr = rule.getAlertEffectivePeriod().split("~");
                LocalTime startTime = LocalTime.parse(arr[0]);
                LocalTime endTime = LocalTime.parse(arr[1]);
                //上报时间
                LocalTime dataTime = LocalDateTimeUtil.of(alarmTime).toLocalTime();
                if (dataTime.isBefore(startTime) || dataTime.isAfter(endTime)) {
                    continue;
                }
                // 找到一条报警规则规则
                //log.info("rule：{}", rule);
                String operator = rule.getOperator();
                Float ruleValue = rule.getValue();
                if (Objects.equals(operator, ">=")) {
                    //触发警告
                    // log.info("data:{} 触发 告警：", JSONUtil.toJsonStr(data),JSONUtil.toJsonStr(rule));
                    parepaeAlert(data, rule);
                } else {
                    if (Float.parseFloat(dataValue) < ruleValue) {
                        //触发警告
                        //log.info("data:{} 触发 告警：", JSONUtil.toJsonStr(data),JSONUtil.toJsonStr(rule));
                        parepaeAlert(data, rule);
                    }
                }
            }
        }
    }

    private void parepaeAlert(DeviceDataVo data, AlertRule rule) {

        //持续周期
        Integer duration = rule.getDuration();

        //读取redis中的旧的持续周期值
        String durationkey = CacheConstants.IOT_DEVICE_ALERT_DURATION + data.getIotId() + ":" + data.getFunctionId() + ":" + rule.getId();
        //把旧的持续周期+1
        Long increment = redisTemplate.opsForValue().increment(durationkey);

        //设置时间，不要超过2个持续周期
        redisTemplate.expire(durationkey, 8, TimeUnit.SECONDS);
        //到达持续周期
        if (increment!=null &&increment >= duration) {
            //获取静默周期的key
            String silentkey = CacheConstants.IOT_DEVICE_ALERT_SILENT + data.getIotId() + ":" + data.getFunctionId() + ":" + rule.getId();
            Boolean exists = redisTemplate.hasKey(silentkey);

            if (Boolean.TRUE.equals(exists)) {
                //处理静默周期的
                log.info(" 处于静默周期");
            } else {
                //发告警
                //设置静默周期
                Integer alertSilentPeriod = rule.getAlertSilentPeriod();
                redisTemplate.opsForValue().set(silentkey, "silent", alertSilentPeriod, TimeUnit.MINUTES);
                //清零持续周期
                redisTemplate.delete(durationkey);
                //报错警告数据 发短信 ....打的电话
                log.info("触发警告");
                triggerAlert(data, rule);
            }
        } else {
            log.info("次数：{}没有到达持续周期");

        }

    }


    private void triggerAlert(DeviceDataVo data, AlertRule rule) {
        // 保存告警数据
        // 获取接收人
        List<Long> userIds = getUserIds(data, rule);
        if (CollectionUtils.isEmpty(userIds)) {
            log.error("没有找到告警接收人，data：{}，rule：{} ", data, rule);
            return;
        }
        // 保存到数据库
        List<AlertData> alertDataList = new ArrayList<>();
        for (Long userId : userIds) {
            AlertData alertData = BeanUtil.copyProperties(data, AlertData.class);
            alertData.setAlertRuleId(rule.getId());
            String alertReason = CharSequenceUtil.format("{}{}{},持续{}个周期就报警", rule.getFunctionName(), rule.getOperator(), rule.getValue(), rule.getDuration());
            alertData.setAlertReason(alertReason);
            alertData.setType(rule.getAlertDataType());
            alertData.setStatus(0);
            alertData.setUserId(userId);
            alertDataList.add(alertData);
        }
        alertDataMapper.batchInsert(alertDataList);
        //TODO 发短信，打电话
        AlertNotifyDto alertNotifyDto = BeanUtil.copyProperties(data, AlertNotifyDto.class);
        alertNotifyDto.setAlertDataType(rule.getAlertDataType());
        alertNotifyDto.setVoiceNotifyStatus(1);
        alertNotifyDto.setNotifyType(1);
        alertNotifyDto.setIsAllConsumer(false);
        WebSocketServer.sendMessageToConsumer(alertNotifyDto,userIds);
    }


    private List<Long> getUserIds(DeviceDataVo data, AlertRule rule){
        // 如果是老人的数据异常，发给护理人员和系统管理员
        Set<Long> userIds = new HashSet<>();
        if(Objects.equals(rule.getAlertDataType(), 0)){
            if(Objects.equals(data.getLocationType(), 0)){
                // 随身设备
                // device表binding_location = 老人的id
                // nursing_elder表中根据老人的id查询到护理人员的id
                List<Long> nursingIds = nursingElderMapper.selectNursingIdByPorTableIoId(data.getIotId());
                if(!CollectionUtils.isEmpty(nursingIds)){
                    userIds.addAll(nursingIds);
                }
            }else{
                // 睡眠检测带，固定设备
                // device表中的binding_location=床的id
                // elder表有bed_id
                // nursing_elder表中根据老人的id查询到护理人员的id
                List<Long> nursingIds = nursingElderMapper.selectNursingIdByFixedIot(data.getIotId());
                if(!CollectionUtils.isEmpty(nursingIds)){
                    userIds.addAll(nursingIds);
                }
            }
        }else{
            // 如果是硬件设备数据异常，发给设备管理员和系统管理员
            List<Long> uIds = userMapper.selectNursingIdByRoleName("维修工");
            if(!CollectionUtils.isEmpty(uIds)){
                userIds.addAll(uIds);
            }
        }
        List<Long> uIds = userMapper.selectNursingIdByRoleName("超级管理员");
        if(!CollectionUtils.isEmpty(uIds)){
            userIds.addAll(uIds);
        }
        log.info("接收人的id：{}", userIds);
        return new ArrayList<>(userIds);
    }
}
